//// GenAPN project main.go
//package main

package main

import (
	"encoding/csv"
	"fmt"
	"io"
	"os"
	//"strconv"
	"github.com/tealeg/xlsx"
	"strings"
)

// APN数据
type ApnData struct {
	Mnc []string
}

// 国家数据
type CTData struct {
	Name string
	Lang string
	Mcc  string
	Apns map[string]*ApnData
}

// 从CSV读取APN
func readCsvFile(filename string) [][]string {
	records := make([][]string, 0)

	file, err := os.Open(filename)
	if err != nil {
		fmt.Println("Error:", err)
		return nil
	}
	defer file.Close()
	reader := csv.NewReader(file)

	i := 0
	for {
		record, err := reader.Read()

		if err == io.EOF {
			break
		} else if err != nil {
			fmt.Println("Error:", err)
			return nil
		}
		if i > 0 {
			records = append(records, record)
		}
		i++
	}
	return records
}

// 从Excel读取APN
func readXlsxFile(filename string) [][]string {
	records := make([][]string, 0)

	xlFile, error := xlsx.OpenFile(filename)
	if error != nil {
		fmt.Println("文件不存在:" + filename)
		return nil
	}

	for _, sheet := range xlFile.Sheets {
		i := 0
		for _, row := range sheet.Rows {
			if i > 0 {
				record := []string{}

				for x := 0; x < 5; x++ {
					record = append(record, row.Cells[x].String())
				}
				records = append(records, record)
			}
			i++
		}
	}
	return records
}

// 读取数据
func readFile() map[string]*CTData {
	datas := make(map[string]*CTData, 0)
	// 从文件读取数据
	apnList := readCsvFile("APN数据.csv")
	//apnList := readXlsxFile("APN数据.xlsx")
	for _, v := range apnList {
		name, lang, mcc, mnc, apn := v[0], v[1], v[2], v[3], v[4]
		//fmt.Printf("%s, %s, %s, %s\n", lang, mcc, mnc, apn) // record has the type []string
		if datas[lang] == nil {
			data := &CTData{Name: name, Lang: lang, Mcc: mcc, Apns: make(map[string]*ApnData, 0)}
			datas[lang] = data
			apnCreate(data, apn, mnc)
		} else {
			data := datas[lang]
			apnCreate(data, apn, mnc)
		}
	}
	return datas
}

// 添加到APN列表
func apnCreate(data *CTData, apn, mnc string) {
	//fmt.Println("create apn")
	if data.Apns[apn] == nil {
		data.Apns[apn] = &ApnData{make([]string, 0)}
	}
	data.Apns[apn].Mnc = append(data.Apns[apn].Mnc, mnc)
}

// 输出到文件
func codeBydy() string {
	datas := readFile()
	lines := "\n"

	for k, v := range datas {
		lines += fmt.Sprintf("#define CL_APN_LANG_%s // %s\n", k, v.Name)
	}
	lines += fmt.Sprintf("\n\n")

	results := []string{}
	// 国家apn数据
	for _, v := range datas {
		v_name := fmt.Sprintf("_apn_lang_%s_%s", strings.ToLower(v.Lang), v.Mcc)

		lines += fmt.Sprintf("static CL_APN_S %s[] = {\n", v_name)
		for k1, v1 := range v.Apns {
			mncs := ""
			for _, mnc := range v1.Mnc {
				//strconv.Itoa(i)
				mncs = mncs + mnc
			}
			lines += fmt.Sprintf("  {\"%s\", \"%s\"},\n", k1, mncs)
		}
		lines += fmt.Sprintf("};\n")

		// 数据
		result := fmt.Sprintf("%s, %d, %s", v.Mcc, len(v.Apns), v_name)
		results = append(results, result)
	}
	lines += fmt.Sprintf("\n")

	// 总数据结构
	lines += fmt.Sprintf("static CL_APN_DATA_S _apns[] = {\n")
	for _, v := range results {
		lines += fmt.Sprintf("    {%s},\n", v)
	}
	lines += fmt.Sprintf("};\n")

	return lines
}

func codeHeader() string {
	return `
#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"

typedef struct
{
    char apn[32];
    char mccs[32];
}CL_APN_S;

typedef struct
{
    short mcc;
	short apn_count;
    CL_APN_S *apn_data;
}CL_APN_DATA_S;
	`
}

func codeBooter() string {
	return `
void cl_GetApnData(char *strImsi, char *strNetApn)
{
    int i=0;
    int max = sizeof(_apns)/sizeof(CL_APN_DATA_S);
    char mcc_str[4] = {0};
    char mnc_str[4] = {0};
    int mcc = 460;
    
    // 转换
    strncpy(mcc_str, strImsi, 3);
    strncpy(mnc_str, strImsi+3, 2);
    mcc = atoi(mcc_str);

    for (i = 0; i < max; i++)
    {
        CL_APN_DATA_S *apn = &_apns[i];        
        int apn_count = sizeof(*apn->apn_data)/sizeof(CL_APN_S);
        int j=0;

        for(j=0;j<apn->apn_count;j++)
        {
            char *p = apn->apn_data[j].mccs;
            if(mcc!=apn->mcc)
                continue;

            while(*p>0) {
                if(memcmp(p, mnc_str, 2) ==0){
                    strcpy(strNetApn, apn->apn_data[j].apn);
                }
                p=p+2;
            }
        }
    }
}
	`
}

func main() {
	fmt.Println(codeHeader())
	fmt.Println(codeBydy())
	fmt.Println(codeBooter())

	wfile, ferr := os.Create("cl_apn.txt")
	if ferr != nil {
		fmt.Println("Failed to create the output file", "cl_apn.c")
		return
	}
	defer wfile.Close()

	wfile.WriteString(codeHeader())
	wfile.WriteString(codeBydy())
	wfile.WriteString(codeBooter())

}
